<!--
/**
 * @Author: 老林头
 * @Date: 2020-12-9 16:21:45
 * @lastAuthor:
 * @lastChangeDate:
 * @description: 滑块拼图组件（需后端支持）
 * @unfinish：样式同意太累了，等闲了再说
 */
-->
<template>
	<view style="position: relative;">
		<view v-if="type === '2'" class="verify-img-out" :style="{ height: parseInt(imgSize.height) + space + 'px' }">
			<view class="verify-img-panel" :style="{ width: imgSize.width, height: imgSize.height }">
				<image :src="backImgBase" alt="" style="width:100%;height:100%;display:block" />
				<view class="verify-refresh" @click="refresh" v-show="showRefresh"><text class="iconfont icon-refresh" /></view>
				<transition name="tips">
					<text class="verify-tips" v-if="tipWords" :style="{ 'background-color': tipsBackColor }">{{ tipWords }}</text>
				</transition>
			</view>
		</view>

		<!-- 公共部分 -->
		<view
			class="verify-bar-area"
			:style="{
				width: imgSize.width,
				height: '40px',
				'line-height': '40px',
				'border-color': sliderBorderColor
			}"
		>
			<text class="verify-msg" v-text="tipsText" />
			<view
				class="verify-left-bar"
				:style="{
					width: leftBarWidth ? leftBarWidth : '40px',
					height: '40px',
					'border-color': sliderBorderColor,
					transaction: transitionWidth
				}"
			/>
			<view
				class="verify-move-block"
				@touchstart="start"
				@touchend="end"
				@touchmove="move"
				:style="{
					width: '40px',
					height: '40px',
					left: moveBlockLeft,
					transition: transitionLeft
				}"
			>
				<text :class="['verify-icon iconfont', iconClass]" :style="{ color: iconColor }" />
				<view
					v-if="type === '2'"
					class="verify-sub-block"
					:style="{
						width: '60px',
						height: imgSize.height,
						top: '-' + (parseInt(imgSize.height) + space) + 'px'
					}"
				>
					<image :src="blockBackImgBase" alt="" style="width:100%;height:100%;display:block"></image>
				</view>
			</view>
		</view>
	</view>
</template>
<script>
/**
 * VerifySlide
 * @description 滑块拼图
 */
import { JSEncrypt } from '../../utils/jsencrypt/jsencrypt.min.js';
import { rsaEncrypt } from '../../utils/index.js';
export default {
	name: 'IuVerifySlide',
	props: {
		// 验证类型，1为滑块验证；2为滑块拼图验证
		type: {
			type: String,
			default: '1'
		},
		// 图片图滑动槽之间间隔
		space: {
			type: Number,
			default: 10
		},
		// 滑动槽文字提示
		explain: {
			type: String,
			default: '向右滑动完成验证'
		},
		// 图片宽高
		imgSize: {
			type: Object,
			default() {
				return {
					width: '310px',
					height: '155px'
				};
			}
		},
		barSize: {
			type: Object,
			default() {
				return {
					width: '100%',
					height: '40px'
				};
			}
		}
	},
	data() {
		return {
			backImgBase: '', // 验证码背景图片
			blockBackImgBase: '',
			startMoveTime: '', // 移动开始的时间
			endMovetime: '', // 移动结束的时间
			tipsBackColor: '', // 提示词的背景颜色
			tipWords: '', // xx秒成功提示词
			tipsText: '',
			// 滑块大小，控制滑块最右移动距离，可为输入参数但不必
			blockSize: {
				width: '50px',
				height: '50px'
			},
			moveBlockLeft: undefined,
			leftBarWidth: undefined,
			slierWidth: 0,
			// 移动中样式
			sliderBorderColor: '#ddd',
			iconColor: undefined,
			iconClass: 'icon-right',
			status: false, // 鼠标状态
			isEnd: false, // 是够验证完成
			showRefresh: true,
			transitionLeft: '',
			transitionWidth: ''
		};
	},
	created() {},
	methods: {
		init() {
			this.tipsText = this.explain;
			this.getPictrue();
			this.$nextTick(() => {
				this.$emit('ready', this);
			});
		},

		//鼠标按下
		start: function(e) {
			this.startMoveTime = new Date().getTime(); //开始滑动的时间
			if (this.isEnd == false) {
				this.iconColor = '#fff';
				e.stopPropagation();
				this.status = true;
			}
		},
		//鼠标移动
		move: function(e) {
			const query = uni.createSelectorQuery().in(this);
			this.barArea = query.select('.verify-bar-area');
			var bar_area_left, barArea_offsetWidth;
			this.barArea
				.boundingClientRect(data => {
					bar_area_left = Math.ceil(data.left);
					this.slierWidth = data.width - 42; // 扣除边框2px和滑块40px
					barArea_offsetWidth = Math.ceil(data.width);
					if (this.status && this.isEnd == false) {
						if (!e.touches) {
							//兼容移动端
							var x = Math.ceil(e.clientX);
						} else {
							//兼容PC端
							var x = Math.ceil(e.touches[0].pageX);
						}
						var move_block_left = x - bar_area_left; // 小方块相对于父元素的left值
						if (this.type !== '1') {
							// 图片滑动
							if (move_block_left >= barArea_offsetWidth - parseInt(parseInt(this.blockSize.width) / 2) - 2) {
								move_block_left = barArea_offsetWidth - parseInt(parseInt(this.blockSize.width) / 2) - 2;
							}
						} else {
							// 普通滑动
							if (move_block_left >= barArea_offsetWidth - parseInt(parseInt(this.barSize.height) / 2) + 3) {
								move_block_left = barArea_offsetWidth - parseInt(parseInt(this.barSize.height) / 2) + 3;
							} else {
								this.finishText = '';
							}
						}
						if (move_block_left <= 0) {
							move_block_left = parseInt(parseInt(this.blockSize.width) / 2);
						}

						//拖动后小方块的left值
						this.moveBlockLeft = move_block_left - parseInt(parseInt(this.blockSize.width) / 2) + 'px';
						this.leftBarWidth = move_block_left - parseInt(parseInt(this.blockSize.width) / 2) + 'px';
					}
				})
				.exec();
		},

		//鼠标松开
		end: function() {
			this.endMovetime = new Date().getTime();
			// 判断是否重合
			if (this.status && this.isEnd == false) {
				if (this.type !== '1') {
					// 图片滑动距离,严谨的应该是移动百分比进行比较
					let moveLeftDistance = parseInt((this.moveBlockLeft || '').replace('px', ''));
					moveLeftDistance = (moveLeftDistance * 310) / parseInt(this.imgSize.width);
					let data = {
						checkJson: rsaEncrypt(moveLeftDistance) // 加密上传
					};

					this.$network({
						url: `image/check`, // 仅为示例，并非真实接口地址。
						data,
						method: 'POST',
						success: result => {
							if (result) {
								this.iconColor = '#fff';
								this.iconClass = 'icon-check';
								this.sliderBorderColor = '#7ac23c';
								this.showRefresh = false;
								this.isEnd = true;
								this.tipsText = '验证成功';
								this.tipsBackColor = 'rgb(92, 184, 92,.5)';
								this.tipWords = `${((this.endMovetime - this.startMoveTime) / 1000).toFixed(2)}s验证成功`;
								this.$emit('success', true);
							} else {
								this.iconColor = '#fff';
								this.iconClass = 'icon-close';
								this.sliderBorderColor = 'red';
								this.tipsBackColor = 'rgb(217, 83, 79,.5)';
								setTimeout(() => {
									this.sliderBorderColor = '#ddd';
									this.refresh();
								}, 1000);
								this.$emit('error', this);
								this.tipWords = '验证失败';
								setTimeout(() => {
									this.tipWords = '';
								}, 1000);
							}
						}
					});
				} else {
					//普通滑动
					let moveWidth = parseInt((this.moveBlockLeft || '').replace('upx', ''));
					if (moveWidth === this.slierWidth) {
						this.sliderBorderColor = '#7ac23c';
						this.iconColor = '#fff';
						this.iconClass = 'icon-check';
						this.showRefresh = false;
						this.tipsText = '验证成功';
						this.isEnd = true;
						this.$emit('success', this);
					} else {
						this.sliderBorderColor = 'red';
						this.iconColor = '#fff';
						this.iconClass = 'icon-close';
						this.isEnd = true;
						this.$emit('error', this);
						// 滑块归位
						const time = setInterval(() => {
							if (moveWidth === 0) {
								this.isEnd = false;
								this.moveBlockLeft = 0;
								this.sliderBorderColor = '#ddd';
								this.iconColor = '#fff';
								this.iconClass = 'icon-right';
								clearInterval(time);
							} else {
								let step = 10;
								moveWidth < 10 ? (step = 1) : (step = 10);
								moveWidth -= step;
								this.leftBarWidth = this.moveBlockLeft = moveWidth + 'px';
							}
						}, 50);
					}
				}
				this.status = false;
			}
		},
		refresh: function() {
			this.showRefresh = true;
			this.transitionLeft = 'left .3s';
			this.moveBlockLeft = 0;
			this.leftBarWidth = false;
			this.transitionWidth = 'width .3s';
			this.iconColor = '#000';
			this.iconClass = 'icon-right';
			this.getPictrue();
			this.isEnd = false;
			setTimeout(() => {
				this.transitionWidth = '';
				this.transitionLeft = '';
				this.tipsText = this.explain;
			}, 300);
		},

		// 请求背景图片和验证图片
		getPictrue() {
			this.$network({
				url: `image/verify`, //仅为示例，并非真实接口地址。
				method: 'GET',
				success: res => {
					this.backImgBase = res.sliderBG;
					this.blockBackImgBase = res.slider;
				}
			});
		}
	},
	watch: {
		// type变化则全面刷新
		type: {
			immediate: true,
			handler() {
				this.init();
			}
		}
	},
	mounted() {}
};
</script>
<style scoped>
.verify-tips {
	position: absolute;
	left: 0px;
	bottom: 0px;
	width: 100%;
	height: 30px;
	background-color: rgb(231, 27, 27, 0.5);
	line-height: 30px;
	color: #fff;
}
.tips-enter-active {
	transition: all 1.5s ease;
}
.tips-leave-active {
	transition: all 1.5s cubic-bezier(1, 0.5, 0.8, 1);
}
.tips-enter,
.tips-leave-to {
	transform: translateY(25px);
	opacity: 0;
}

/*滑动验证码*/
.verify-bar-area {
	position: relative;
	background: #ffffff;
	text-align: center;
	-webkit-box-sizing: content-box;
	-moz-box-sizing: content-box;
	box-sizing: content-box;
	border: 1px solid #ddd;
	-webkit-border-radius: 12rpx;
}

.verify-bar-area .verify-move-block {
	position: absolute;
	top: 0px;
	left: 0;
	background: #fff;
	cursor: pointer;
	-webkit-box-sizing: content-box;
	-moz-box-sizing: content-box;
	box-sizing: content-box;
	box-shadow: 0 0 2px #888888;
	border-top-left-radius: 10rpx;
	border-bottom-left-radius: 10rpx;
	border-top-right-radius: 6rpx;
	border-bottom-right-radius: 6rpx;
}

.verify-bar-area .verify-left-bar {
	position: absolute;
	top: -1px;
	left: -1px;
	background: #419041;
	cursor: pointer;
	-webkit-box-sizing: content-box;
	-moz-box-sizing: content-box;
	box-sizing: content-box;
	border: 1px solid #000;
	opacity: 0.5;
	border-top-left-radius: 12rpx;
	border-bottom-left-radius: 12rpx;
}

.verify-img-panel {
	margin: 0;
	-webkit-box-sizing: content-box;
	-moz-box-sizing: content-box;
	box-sizing: content-box;
	border: 1px solid #ddd;
	border-radius: 16rpx;
	position: relative;
	overflow: hidden;
}

.verify-img-panel .verify-refresh {
	width: 25px;
	height: 25px;
	text-align: center;
	padding: 5px;
	cursor: pointer;
	position: absolute;
	top: 0;
	right: 0;
	z-index: 2;
}

.verify-img-panel .icon-refresh {
	font-size: 20px;
	color: #fff;
}

.verify-bar-area .verify-move-block .verify-sub-block {
	position: absolute;
	text-align: center;
	z-index: 3;
	/* border: 1px solid #fff; */
}

.verify-bar-area .verify-move-block .verify-icon {
	font-size: 18px;
}

.verify-bar-area .verify-msg {
	z-index: 3;
}

.iconfont {
	font-family: 'iconfont' !important;
	font-size: 16px;
	font-style: normal;
	-webkit-font-smoothing: antialiased;
	-moz-osx-font-smoothing: grayscale;
}

.icon-check:before {
	content: ' ';
	display: block;
	width: 40rpx;
	height: 40rpx;
	position: absolute;
	margin: auto;
	left: 0;
	right: 0;
	top: 0;
	bottom: 0;
	z-index: 9999;
	background-image: url('');
	background-size: contain;
}

.icon-close:before {
	content: ' ';
	display: block;
	width: 40rpx;
	height: 40rpx;
	position: absolute;
	margin: auto;
	left: 0;
	right: 0;
	top: 0;
	bottom: 0;
	z-index: 9999;
	background-image: url('');
	background-size: contain;
}

.icon-right:before {
	content: ' ';
	display: block;
	width: 40rpx;
	height: 40rpx;
	position: absolute;
	margin: auto;
	left: 0;
	right: 0;
	top: 0;
	bottom: 0;
	background-size: cover;
	z-index: 9999;
	background-image: url('');
	background-size: contain;
}

.icon-refresh:before {
	content: ' ';
	display: block;
	width: 16px;
	height: 16px;
	position: absolute;
	margin: auto;
	left: 0;
	right: 0;
	top: 0;
	bottom: 0;
	z-index: 9999;
	background-image: url('');
	background-size: contain;
}
</style>
